package clist

import (
	"acs/hash"
	"container/list"
)

//线程安全的list，在添加时需要key作为hash的数据
type ConcurrentList []*ConcurrentListShard

func New(size int) ConcurrentList {
	clist := make([]*ConcurrentListShard, size)
	for i := 0; i < size; i++ {
		clist[i] = &ConcurrentListShard{
			items: list.New(),
		}
	}
	return clist
}

func (this ConcurrentList) GetShard(key string) *ConcurrentListShard {
	h := hash.NewMurmur3C()
	h.Write([]byte(key))
	idx := uint(h.Sum32()) & uint(len(this)-1)
	return this[idx]
}

func (this ConcurrentList) Append(key string, value interface{}) *list.Element {
	shard := this.GetShard(key)
	shard.Lock()
	defer shard.Unlock()
	return shard.items.PushBack(value)
}

func (this ConcurrentList) Remove(key string, e *list.Element) interface{} {
	shard := this.GetShard(key)
	shard.Lock()
	defer shard.Unlock()
	return shard.items.Remove(e)
}

func (this ConcurrentList) Count() int {
	count := 0
	for _, shard := range this {
		shard.RLock()
		count += shard.items.Len()
		shard.RUnlock()
	}
	return count
}

func (this ConcurrentList) Iter() <-chan interface{} {
	ch := make(chan interface{})
	go this.iter(ch)
	return ch
}

func (this ConcurrentList) IterBuffered() <-chan interface{} {
	ch := make(chan interface{}, this.Count())
	go this.iter(ch)
	return ch
}

func (this ConcurrentList) iter(ch chan<- interface{}) {
	for _, shard := range this {
		shard.RLock()
		items := shard.items
		for e := items.Front(); e != nil; e = e.Next() {
			ch <- e.Value
		}
		shard.RUnlock()
	}
	close(ch)
}
